//
// Created by YueChuan on 2023/5/1.
//

#ifndef __YUECHUAN_TCP_SERVER_H
#define __YUECHUAN_TCP_SERVER_H

#include <memory>
#include <functional>
#include <vector>
#include <map>
#include "socket.h"
#include "iomanager.h"
#include "noncopyable.h"
#include "config.h"
#include "address.h"

namespace yuechuan {

    struct TcpServerConf {
        typedef std::shared_ptr<TcpServerConf> ptr;

        /// 地址数组
        std::vector<std::string> address;
        /// 是否保持连接
        int keepalive = 0;
        /// 超时时间
        int timeout = 1000 * 2 * 60;
        /// 是否是ssl连接
        int ssl = 0;
        /// 连接id
        std::string id;

        /// 连接类型
        std::string type = "http";
        /// 服务名称
        std::string name;
        /// 证书文件名称
        std::string cert_file;
        /// 证书私钥文件
        std::string key_file;
        /// 服务器接收连接的协程调度器的名称
        std::string accept_worker;
        /// 进行io的协程调度器名称
        std::string io_worker;
        /// 客户端进行链接的协程调度器名称
        std::string process_worker;
        /// 额外的参数
        std::map<std::string, std::string> args;

        /**
         * @brief 是否非法
         * @return bool
         */
        bool isValid() const { return !address.empty(); }

        /**
         * @brief 重写用于比较相等的运算
         * @param oth 要比较的对象
         * @return bool
         */
        bool operator==(const TcpServerConf &oth) const {
            return address == oth.address &&
                   keepalive == oth.keepalive &&
                   timeout == oth.timeout &&
                   ssl == oth.ssl &&
                   id == oth.id &&
                   type == oth.type &&
                   name == oth.name &&
                   cert_file == oth.cert_file &&
                   key_file == oth.key_file &&
                   accept_worker == oth.accept_worker &&
                   io_worker == oth.io_worker &&
                   process_worker == oth.process_worker;
        }
    };

    template<>
    class LexicalCast<std::string, TcpServerConf> {
    public:
        TcpServerConf operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            TcpServerConf conf;
            conf.id = node["id"].as<std::string>(conf.id);
            conf.type = node["type"].as<std::string>(conf.type);
            conf.keepalive = node["keepalive"].as<int>(conf.keepalive);
            conf.timeout = node["timeout"].as<int>(conf.timeout);
            conf.name = node["name"].as<std::string>(conf.name);
            conf.ssl = node["ssl"].as<int>(conf.ssl);
            conf.cert_file = node["cert_file"].as<std::string>(conf.cert_file);
            conf.key_file = node["key_file"].as<std::string>(conf.key_file);
            conf.accept_worker = node["accept_worker"].as<std::string>();
            conf.io_worker = node["io_worker"].as<std::string>();
            conf.process_worker = node["process_worker"].as<std::string>();

            conf.args = LexicalCast<std::string, std::map<std::string, std::string> >()(
                    node["args"].as<std::string>(""));
            if (node["address"].IsDefined()) {
                for (size_t i = 0; i < node["address"].size(); ++i) {
                    conf.address.emplace_back(node["address"][i].as<std::string>());
                }
            }
            return conf;
        }
    };

    template<>
    class LexicalCast<TcpServerConf, std::string> {
    public:
        std::string operator()(const TcpServerConf &conf) {
            YAML::Node node;
            node["id"] = conf.id;
            node["type"] = conf.type;
            node["name"] = conf.name;
            node["keepalive"] = conf.keepalive;
            node["timeout"] = conf.timeout;
            node["ssl"] = conf.ssl;
            node["cert_file"] = conf.cert_file;
            node["key_file"] = conf.key_file;
            node["accept_worker"] = conf.accept_worker;
            node["io_worker"] = conf.io_worker;
            node["process_worker"] = conf.process_worker;
            node["args"] = YAML::Load(LexicalCast<std::map<std::string, std::string>, std::string>()(conf.args));
            for (auto &i: conf.address) {
                node["address"].push_back(i);
            }
            std::stringstream ss;
            ss << node;
            return ss.str();
        }
    };

    /**
     * @brief TCP服务器的封装
     */
    class TcpServer : public std::enable_shared_from_this<TcpServer>, Noncopyable {
    public:
        typedef std::shared_ptr<TcpServer> ptr;

        /**
         * @brief 含参构造函数
         * @param worker socket客户端工作的协程调度器
         * @param ioWork
         * @param acceptWork 服务器socket执行接收socket连接的协程调度器
         */
        TcpServer(IOManager *worker = IOManager::GetThis(), IOManager *ioWork = IOManager::GetThis(),
                  IOManager *acceptWork = IOManager::GetThis());

        /**
         * @brief 析构函数
         */
        virtual ~TcpServer();

        /**
         * @brief 绑定地址
         * @param addr 要绑定的地址
         * @param ssl 是否是ssl地址
         * @return
         */
        virtual bool bind(Address::ptr addr, bool ssl = false);

        /**
         * @brief 绑定地址数组
         * @param addrs 需要绑定的地址数组
         * @param fails 绑定失败的地址数组
         * @param ssl 是否是ssl
         * @return
         */
        virtual bool bind(const std::vector<Address::ptr> &addrs, std::vector<Address::ptr> &fails, bool ssl = false);

        /**
         * @brief 加载ssl证书
         * @param cert_file 证书
         * @param key_file  私钥文件
         * @return
         */
        bool loadCertificates(const std::string &cert_file, const std::string &key_file);

        /**
         * @brief 启动服务
         * @return
         */
        virtual bool start();

        /**
         * @brief 停止服务
         * @return bool
         */
        virtual void stop();

        /**
         * @brief 返回读取超时时间
         * @return uint64_t
         */
        uint64_t getRecvTimeout() const { return m_recvTimeout; }

        /**
         * @brief 返回服务器名称
         * @return std::string
         */
        std::string getName() const { return m_name; }

        /**
         * @brief 设置服务器名称
         * @param name 要设置的服务器名称
         */
        virtual void setName(const std::string &name) { m_name = name; }

        /**
         * @brief 是否停止
         * @return
         */
        bool isStop() const { return m_isStop; }

        /**
         * @brief 获取Server配置
         * @return TcpServerConf::ptr
         */
        TcpServerConf::ptr getConf() const { return m_conf; }

        /**
         * @brief 设置Server配置
         * @param v 配置智能指针对象
         */
        void setConf(TcpServerConf::ptr &v) { m_conf = v; }

        /**
         * @brief 设置Server配置
         * @param v 配置对象
         */
        void setConf(const TcpServerConf &v);

        /**
         * @brief 转换为字符串输出
         * @param prefix 前缀字符串串
         * @return std::string
         */
        virtual std::string toString(const std::string &prefix = "");

        /**
         * @brief 获取socket连接的socket数组
         * @return std::vector<Socket::ptr>
         */
        std::vector<Socket::ptr> getSocks() const { return m_socks; }

    protected:
        /**
         * @brief 处理新连接的Socket类
         * @param client
         */
        virtual void handleClient(Socket::ptr client);

        /**
         * @brief 开始接收连接
         * @param sock
         */
        virtual void startAccept(Socket::ptr sock);


    private:
        /// 监听socket数组
        std::vector<Socket::ptr> m_socks;

        /// 新连接的Socket工作的调度器
        IOManager *m_work;
        IOManager *m_ioWorker;
        /// 服务器Socket接受连接的调度器
        IOManager *m_acceptWorker;

        /// 接收超时时间
        uint64_t m_recvTimeout;
        /// 服务器的名称
        std::string m_name;
        /// 服务器的类型，默认为tcp
        std::string m_type = "tcp";
        /// 服务器是否停止
        bool m_isStop;
        /// 是否是SSL连接，默认为false
        bool m_ssl = false;

        /// 服务配置
        TcpServerConf::ptr m_conf;
    };
}


#endif //YUECHUAN_TCP_SERVER_H
